1 package org.apache.solr.handler;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import java.lang.invoke.MethodHandles;
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.Future;
25
26 import org.apache.lucene.codecs.CodecUtil;
27 import org.apache.lucene.index.SegmentInfos;
28 import org.apache.lucene.store.Directory;
29 import org.apache.lucene.store.FSDirectory;
30 import org.apache.lucene.store.IOContext;
31 import org.apache.lucene.store.IndexInput;
32 import org.apache.lucene.util.Version;
33 import org.apache.solr.common.SolrException;
34 import org.apache.solr.core.DirectoryFactory;
35 import org.apache.solr.core.SolrCore;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class RestoreCore implements Callable<Boolean> {
40
41 private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
42
43 private final String backupName;
44 private final String backupLocation;
45 private final SolrCore core;
46
47 public RestoreCore(SolrCore core, String location, String name) {
48 this.core = core;
49 this.backupLocation = location;
50 this.backupName = name;
51 }
52
53 @Override
54 public Boolean call() throws Exception {
55 return doRestore();
56 }
57
58 private boolean doRestore() throws Exception {
59
60 Path backupPath = Paths.get(backupLocation).resolve(backupName);
61 String restoreIndexName = "restore." + backupName;
62 String restoreIndexPath = core.getDataDir() + restoreIndexName;
63
64 Directory restoreIndexDir = null;
65 Directory indexDir = null;
66 try (Directory backupDir = FSDirectory.open(backupPath)) {
67
68 final Version version = IndexFetcher.checkOldestVersion(SegmentInfos.readLatestCommit(backupDir));
69
70 restoreIndexDir = core.getDirectoryFactory().get(restoreIndexPath,
71 DirectoryFactory.DirContext.DEFAULT, core.getSolrConfig().indexConfig.lockType);
72
73
74 indexDir = core.getDirectoryFactory().get(core.getIndexDir(),
75 DirectoryFactory.DirContext.DEFAULT, core.getSolrConfig().indexConfig.lockType);
76
77
78 for (String filename : backupDir.listAll()) {
79 checkInterrupted();
80 log.info("Copying file {} to restore directory ", filename);
81 try (IndexInput indexInput = backupDir.openInput(filename, IOContext.READONCE)) {
82 Long checksum = null;
83 try {
84 checksum = CodecUtil.retrieveChecksum(indexInput);
85 } catch (Exception e) {
86 log.warn("Could not read checksum from index file: " + filename, e);
87 }
88 long length = indexInput.length();
89 IndexFetcher.CompareResult compareResult = IndexFetcher.compareFile(indexDir, version, filename, length, checksum);
90 if (!compareResult.equal || (!compareResult.checkSummed && (filename.endsWith(".si")
91 || filename.endsWith(".liv") || filename.startsWith("segments_")))) {
92 restoreIndexDir.copyFrom(backupDir, filename, filename, IOContext.READONCE);
93 } else {
94
95 restoreIndexDir.copyFrom(indexDir, filename, filename, IOContext.READONCE);
96 }
97 } catch (Exception e) {
98 throw new SolrException(SolrException.ErrorCode.UNKNOWN, "Exception while restoring the backup index", e);
99 }
100 }
101 log.debug("Switching directories");
102 IndexFetcher.modifyIndexProps(core, restoreIndexName);
103
104 boolean success;
105 try {
106 core.getUpdateHandler().newIndexWriter(false);
107 openNewSearcher();
108 success = true;
109 log.info("Successfully restored to the backup index");
110 } catch (Exception e) {
111
112 log.warn("Could not switch to restored index. Rolling back to the current index");
113 Directory dir = null;
114 try {
115 dir = core.getDirectoryFactory().get(core.getDataDir(), DirectoryFactory.DirContext.META_DATA,
116 core.getSolrConfig().indexConfig.lockType);
117 dir.deleteFile(IndexFetcher.INDEX_PROPERTIES);
118 } finally {
119 if (dir != null) {
120 core.getDirectoryFactory().release(dir);
121 }
122 }
123
124 core.getDirectoryFactory().doneWithDirectory(restoreIndexDir);
125 core.getDirectoryFactory().remove(restoreIndexDir);
126 core.getUpdateHandler().newIndexWriter(false);
127 openNewSearcher();
128 throw new SolrException(SolrException.ErrorCode.UNKNOWN, "Exception while restoring the backup index", e);
129 }
130 if (success) {
131 core.getDirectoryFactory().doneWithDirectory(indexDir);
132 core.getDirectoryFactory().remove(indexDir);
133 }
134
135 return true;
136 } finally {
137 if (restoreIndexDir != null) {
138 core.getDirectoryFactory().release(restoreIndexDir);
139 }
140 if (indexDir != null) {
141 core.getDirectoryFactory().release(indexDir);
142 }
143 }
144 }
145
146 private void checkInterrupted() throws InterruptedException {
147 if (Thread.currentThread().isInterrupted()) {
148 throw new InterruptedException("Stopping restore process. Thread was interrupted.");
149 }
150 }
151
152 private void openNewSearcher() throws Exception {
153 Future[] waitSearcher = new Future[1];
154 core.getSearcher(true, false, waitSearcher, true);
155 if (waitSearcher[0] != null) {
156 waitSearcher[0].get();
157 }
158 }
159 }